package service;

import annotation.DependencyInjection;
import annotation.Singleton;
import entity.Message;
import entity.Relation;
import repository.MessageRepository;
import repository.RelationRepository;
import response.message.MessageListResponse;
import response.message.MessagePullResponse;
import response.message.MessageSendResponse;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

@Singleton
public class MessageService {
    private MessageRepository messageRepository;
    private RelationRepository relationRepository;

    @DependencyInjection
    public MessageService(MessageRepository messageRepository, RelationRepository relationRepository) {
        this.messageRepository = messageRepository;
        this.relationRepository = relationRepository;
    }

    public MessageListResponse getBothMessages(String senderUsername, String receiverUsername) {
        relationRepository.startWrite();
        messageRepository.startRead();
        try {
            LocalDateTime now = LocalDateTime.now();
            List<Message> senderMessageList = messageRepository.get(senderUsername, receiverUsername, now);
            List<Message> receiverMessageList = messageRepository.get(receiverUsername, senderUsername, now);
            relationRepository.updateTimestamp(senderUsername, receiverUsername, now);
            senderMessageList.addAll(receiverMessageList);
            List<Message> messageList = senderMessageList.stream().sorted(Comparator.comparing(Message::getTime)).collect(Collectors.toList());
            return new MessageListResponse(messageList);
        } finally {
            relationRepository.endWrite();
            messageRepository.endRead();
        }
    }

    public MessagePullResponse getLatestMessages(String senderUsername, String receiverUsername) {
        relationRepository.startWrite();
        messageRepository.startRead();
        try {
            Relation relation = relationRepository.get(senderUsername, receiverUsername);
            if (relation == null) {
                return new MessagePullResponse(new ArrayList<>());
            }

            LocalDateTime lastTime = relation.getTimestamp();
            LocalDateTime now = LocalDateTime.now();
            List<Message> messageList = messageRepository.get(senderUsername, receiverUsername, lastTime, now);
            relationRepository.updateTimestamp(senderUsername, receiverUsername, now);
            return new MessagePullResponse(messageList);
        } finally {
            relationRepository.endWrite();
            messageRepository.endRead();
        }
    }

    public MessageSendResponse sendMessage(Message message) {
        messageRepository.startWrite();
        try {
            message.setTime(LocalDateTime.now()); // clock synchronization
            messageRepository.add(message);
            return new MessageSendResponse(true);
        } finally {
            messageRepository.endWrite();
        }
    }
}
